﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Soundteller.Audio.Model;
using System.Linq;

namespace Soundteller.Audio.Tests.Unit.Services.MetronomeSpecifications
{
    [TestClass]
    public class WhenTick : MetronomeTestBase
    {
        private List<Sound> _soundsToBeat;

        protected override TimeSpan ElapsedTime
        {
            get { return TimeSpan.FromMilliseconds(13000); }
        }

        protected override void Arrange()
        {
            base.Arrange();

            _soundsToBeat = new List<Sound> { new Sound() };
            var song = new Song();
            song.Sounds.AddRange(_soundsToBeat);

            SongRepository.Setup(r => r.GetActiveSong()).Returns(song);
        }

        [TestMethod]
        public void ThenTimeShouldBeUpdated()
        {
            SongRepository.Verify(r => r.Update(It.IsAny<Song>()), Times.Once());
            Assert.AreEqual(13000, UpdatedSong.Time.TotalMilliseconds);
        }

        [TestMethod]
        public void ThenBeatShouldBeUpdated()
        {
            BeatRepository.Verify(r => r.Update(It.IsAny<double>()), Times.Once());
        }

        [TestMethod]
        public void ThenSoundsShouldBeBuffered()
        {
            SoundBufferRepository.Verify(s => s.Push(It.IsAny<Sound>()), Times.Exactly(_soundsToBeat.Count()));
        }
    }

    [TestClass]
    public class WhenTickGivenLoopEnabledAndSmallerThanEndBeat : MetronomeTestBase
    {
        protected override TimeSpan ElapsedTime
        {
            get { return TimeSpan.FromMilliseconds(12000); }
        }

        protected override void Arrange()
        {
            base.Arrange();
            SongRepository.Setup(r => r.GetActiveSong()).Returns(new Song { LoopEnabled = true, EndBeat = 13, Bpm = 60 });
            BeatCalculator.Setup(b => b.Calculate(It.IsAny<TimeSpan>(), It.IsAny<double>())).Returns(11);
        }

        [TestMethod]
        public void ThenSongShouldNotBeReset()
        {
            Assert.AreEqual(12000, UpdatedSong.Time.TotalMilliseconds);
        }
    }

    [TestClass]
    public class WhenTickGivenLoopEnabledAndEqualToEndBeat : MetronomeTestBase
    {
        private Song _song;

        protected override TimeSpan ElapsedTime
        {
            get { return TimeSpan.FromMilliseconds(13000); }
        }

        protected override void Arrange()
        {
            base.Arrange();
            _song = new Song { LoopEnabled = true, EndBeat = 13, Bpm = 60, Sounds = new List<Sound>() { new Sound{ IsBuffered = false } } };
            SongRepository.Setup(r => r.GetActiveSong()).Returns(_song);

            BeatCalculator.Setup(b => b.Calculate(It.IsAny<TimeSpan>(), It.IsAny<double>())).Returns(13);
        }

        [TestMethod]
        public void ThenSongShouldBeReset()
        {
            Assert.AreEqual(0, UpdatedSong.Time.TotalMilliseconds);
            BeatRepository.Verify(r => r.Update(0), Times.Once());
            Assert.IsTrue(_song.Sounds.All(s => s.IsBuffered == false));
        }
    }

    [TestClass]
    public class WhenTickGivenLoopEnabledAndGreaterThanEndBeat : MetronomeTestBase
    {
        protected override TimeSpan ElapsedTime
        {
            get { return TimeSpan.FromMilliseconds(14000); }
        }

        protected override void Arrange()
        {
            base.Arrange();
            SongRepository.Setup(r => r.GetActiveSong()).Returns(new Song { LoopEnabled = true, EndBeat = 13, Bpm = 60 });
            BeatCalculator.Setup(b => b.Calculate(It.IsAny<TimeSpan>(), It.IsAny<double>())).Returns(14);
        }

        [TestMethod]
        public void ThenSongShouldBeReset()
        {
            Assert.AreEqual(0, UpdatedSong.Time.TotalMilliseconds);
        }
    }
}
